#!/usr/bin/env python
"""
Copyright 2010 Kimmo Parviainen-Jalanko
All rights reserved.

Released under the MIT license, see LICENSE.txt for details.
VERSION = "0.3.2"

Requirements:
    PalmDB module (can be installed from pip - requires 4Suite-XML, pip
    install for 4Suite-XML seems to bug, but it can be found from yum)
    PyQt4 or PySide


"""

VERSION = "0.2"
# Standard & 3rd party libraries
import sys
from optparse import OptionParser
from PySide.QtGui import *
from PySide.QtCore import *
#from PyQt4.QtGui import *
#from PyQt4.QtCore import *


# Our own stuff
import kindle


def LOG(n, s):
    print("{0:d}:{1:>s}".format(n, s))


def report_status(at, total, fn):
    print("Reading file %s (%d/%d)" % (fn, at, total))


class Application(QApplication):
    def __init__(self, argv):
        QApplication.__init__(self, argv)
        self.json = None
        self.books = None
        self.setWindowIcon(QIcon("icons/man.png"))

    def save_json(self):
        if self.json:
            kindle.save_data(self.json)
        else:
            QMessageBox.critical(self.mw, "Error", "There is no data to save")

    def load_json(self):
        self.json = kindle.load_data()
        progress = QProgressDialog("Reading books",
                "Cancel",
                0,
                kindle.get_bookcount() - 1,
                self.mw)
        progress.setWindowModality(Qt.WindowModal)
        self.books = kindle.get_books(progress.setValue)

    def create_collection(self):
        table = self.mw.table
        name, ok = QInputDialog.getText(self.mw,
                'Create collection', 'Enter collection name')
        if ok:
            kindle.add_collection(self.json, name)
            col = table.columnCount()
            table.setColumnCount(col + 1)
            item = QTableWidgetItem(name)
            table.setHorizontalHeaderItem(col, item)
            for row in range(table.rowCount()):
                LOG(4, "(row %d, col %d)" % (row, col))
                item = CheckBox()
                item.setCheckState(False)
                table.setItem(row, col, item)

        else:
            LOG(4, "Collection creation cancelled")

    def delete_collection(self):
        collections = [x.replace("@en-US", "") for x in self.json.keys()]
        table = self.mw.table
        columns = dict([(table.horizontalHeaderItem(n).text(), n) for n in
            range(4, table.columnCount())])
        LOG(4, "Columns: %s" % repr(columns))
        name, ok = QInputDialog.getItem(self.mw, "Delete collection?",
                "Collection:", collections, 0, False)
        if ok:
            kindle.delete_collection(self.json, name)
            table.removeColumn(columns[name])
        else:
            LOG(4, "Collection deletion cancelled")


class CheckBox(QTableWidgetItem):
    def __init__(self):
        QTableWidgetItem.__init__(self, 1000)
        self.setTextAlignment(Qt.AlignVCenter | Qt.AlignJustify)
        self.setFlags(Qt.ItemFlags(
            Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable))


class Table(QTableWidget):
    def __init__(self):
        QTableWidget.__init__(self)
        QTableWidget.setSortingEnabled(self, True)

    def stateChanged(self, row, col):
        if col < 4:
            return

        json_data = QApplication.instance().json

        checked = self.item(row, col).checkState()
        LOG(3, "Item (%d,%d) is %d" % (row, col, checked))
        headeritem = QTableWidget.horizontalHeaderItem(self, col)

        collection = headeritem.text()
        hash = QTableWidget.item(self, row, 0).text()

        if checked:
            LOG(3, "Adding item %s to collection %s" % (hash, collection))
            kindle.add_item(json_data, str(collection), str(hash))
        else:
            LOG(3, "Removing item %s from collection %s" % (hash, collection))
            kindle.remove_item(json_data, str(collection), str(hash))

        s = "%s (%d)" % (collection,
                len(kindle.get_books_in_collection(json_data, collection)))
        headeritem.setStatusTip(s)
        headeritem.setToolTip(s)


class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        screen = QDesktopWidget().screenGeometry()
        self.resize(screen.width(), screen.height())
        self.move(0, 0)
        self.setWindowTitle('Kiehinen')

        # Create controls
        menubar = self.menuBar()
        filemenu = menubar.addMenu('&File')
        helpmenu = menubar.addMenu('&Help')
        self.toolbar = self.addToolBar('Tools')

        # Create actions
        load = QAction(QIcon('icons/fileopen.png'), 'Load', self)
        load.setShortcut('Ctrl+L')
        load.setStatusTip("Load book data")
        self.connect(load, SIGNAL('triggered()'), self.load_data)

        save = QAction(QIcon('icons/filesave.png'), 'Save', self)
        save.setShortcut('Ctrl+S')
        save.setStatusTip("Save book data")
        self.connect(save, SIGNAL('triggered()'),
                QApplication.instance().save_json)

        new_coll = QAction(QIcon('icons/edit_add.png'),
                'New collection', self)
        new_coll.setStatusTip("Create a new collection")
        self.connect(new_coll, SIGNAL('triggered()'),
                QApplication.instance().create_collection)

        remove_coll = QAction(QIcon('icons/edit_remove.png'),
                'Remove collection', self)
        remove_coll.setStatusTip("Delete a collection")
        self.connect(remove_coll, SIGNAL('triggered()'),
                QApplication.instance().delete_collection)

        exit = QAction(QIcon('icons/exit.png'), 'Exit', self)
        exit.setShortcut('Ctrl+Q')
        exit.setStatusTip("Quit program")
        self.connect(exit, SIGNAL('triggered()'), SLOT('close()'))

        about = QAction('About', self)
        self.connect(about, SIGNAL('triggered()'), self.show_about)

        # Populate menus
        filemenu.addAction(load)
        filemenu.addAction(save)
        filemenu.addSeparator()
        filemenu.addAction(exit)

        helpmenu.addAction(about)

        # Populate toolbars
        self.toolbar.addAction(load)
        self.toolbar.addAction(save)
        self.toolbar.addSeparator()
        self.toolbar.addAction(new_coll)
        self.toolbar.addAction(remove_coll)

        # Crete the main table
        self.table = Table()
        self.setCentralWidget(self.table)

        # Connect signals to slots

        self.statusBar().showMessage("Ready")
        self.counter = QLabel("0 books")
        self.counter.setFrameStyle(QFrame.Sunken)
        self.statusBar().addPermanentWidget(self.counter)

    def report_progress(self, at, total, fn):
        self.statusBar().showMessage("Reading file %d/%d (%s)"
            % (at, total, fn))

    def load_data(self):
        self.statusBar().showMessage("Getting the list of eBook files")
        QApplication.instance().load_json()
        self.create_table()

    def show_about(self):
        QMessageBox.about(self,
                "About kiehinen v%s" % VERSION,
                open("about.html", "r").read())

    def create_table(self):
        books = QApplication.instance().books
        json_data = QApplication.instance().json

        collabels = [
                'Hash',
                'Title',
                'Author',
                'Language'] + [
            x.replace('@en-US', '') for x in json_data.keys()]

        self.table.setColumnCount(len(collabels))

        for n, label in enumerate(collabels):
            item = QTableWidgetItem(label)
            self.table.setHorizontalHeaderItem(n, item)

        for row, (hash, book) in enumerate(books.items()):
            self.table.insertRow(row)
            for col, field in enumerate((
                hash,
                book.title,
                book.author,
                book.language)):
                LOG(4, "Populating row %d col: %d with %s" % (row, col, field))
                item = QTableWidgetItem(field)
                item.setTextColor(QColor('black'))
                item.setFlags(Qt.ItemFlags(
                    Qt.ItemIsSelectable | Qt.ItemIsEnabled))
                self.table.setItem(row, col, item)

            for n, v in enumerate(json_data.values()):
                LOG(4, "Populating row %d col: %d with %r" % (
                    row, col + n + 1, hash in v['items']))
                item = CheckBox()
                item.setCheckState(Qt.CheckState(hash in v['items']))
                self.table.setItem(row, col + n + 1, item)

        self.table.resizeColumnsToContents()
        #self.table.resizeRowsToContents()
        self.table.verticalHeader().hide()
        self.table.setColumnHidden(0, True)
        self.counter.setText("%d books" % len(books))

        self.connect(self.table, SIGNAL('cellChanged(int, int)'),
                       self.table.stateChanged)


def main():
    usage = "usage: %prog [options]"
    p = OptionParser(usage=usage, version=VERSION)
    p.add_option('--new', '-n', help="create a new collection")
    p.add_option('--delete', '-d', help="delete a collection")
    p.add_option('--remove', '-r', help="remove an item from a collection")
    p.add_option('--add', '-a', help="add an item to a collection")
    p.add_option('--no-gui', '-x', action="store_false", dest="use_gui",
        help="do not use the QT interface", default=True)
    p.add_option('--list', '-l', action="store_true", dest="list",
        help="list collections", default=False)

    options, args = p.parse_args()

    if options.use_gui:
        app = Application(sys.argv)
        app.mw = MainWindow()
        app.mw.show()
        sys.exit(app.exec_())

    kjd = kindle.load_data()

    # Process options
    if options.new:
        kindle.add_collection(kjd, options.new)
    elif options.delete:
        kindle.delete_collection(kjd, options.delete)
    elif options.list:
        for key in kjd.keys():
            LOG(2, "Found collection %s" % str(key.split('@')[0]))
        books = kindle.get_books(report_status)
        LOG(2, "Found %d books" % len(books))
        for hash, book in books.items():
            print("%s" % hash)
    elif options.add:
        kindle.add_item(kjd, options.add, args[0])
    elif options.remove:
        kindle.remove_item(kjd, options.remove, args[0])

    # Write back to file
    kindle.save_data(kjd)

if __name__ == '__main__':
    main()
